#include "MainFrame/CentralWidget/ImageViewArea.h"
#include <QGraphicsScene>

#include <QMouseEvent>

#include "IRIVIAProject.h"

#include "IRIVIATool.h"
#include <math.h>

#define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height()

ImageViewArea::ImageViewArea(QWidget *parent) :
    QGraphicsView(parent),
    m_pGraphicsScene(nullptr),
    m_scale(1.0),
    m_zoomDelta(0.1),
    m_translateSpeed(1),
    m_bMouseTranslate(false),
    m_translateButton(Qt::MiddleButton)
{
    initWidget();
}

ImageViewArea::~ImageViewArea()
{

}

void ImageViewArea::initWidget()
{
    this->setMouseTracking(true);
    m_pGraphicsScene = new QGraphicsScene(this);
    this->setScene(m_pGraphicsScene);
}

void ImageViewArea::zoomIn()
{
    zoom(1 + m_zoomDelta);
}

void ImageViewArea::zoomOut()
{
    zoom(1 - m_zoomDelta);
}

void ImageViewArea::zoom(float scaleFactor)
{
    qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
    if (factor < 0.07 || factor > 100)
        return;
    scale(scaleFactor, scaleFactor);
    m_scale *= scaleFactor;
}

void ImageViewArea::translate(QPointF delta)
{
    delta *= m_scale;
    delta *= m_translateSpeed;
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    QPoint newCenter(VIEW_WIDTH / 2 - delta.x(), VIEW_HEIGHT / 2 - delta.y());
    centerOn(mapToScene(newCenter));
    setTransformationAnchor(QGraphicsView::AnchorViewCenter);
}

void ImageViewArea::mousePressEvent(QMouseEvent *event)
{
    QPointF cursorpos = mapToScene(event->pos());

    switch(m_enCurToolState) {
    case PencilTool:
        if(event->buttons() & Qt::LeftButton)
        {
            IRIVIATool().applyOnScreen("Pencil", (int)cursorpos.x(), (int)cursorpos.y());
        }
        break;
    case EraserTool:
        if(event->buttons() & Qt::LeftButton)
        {
            IRIVIATool().applyOnScreen("Eraser", (int)cursorpos.x(), (int)cursorpos.y());
        }
        break;
    case BlurOrSharpenTool:
        if(event->buttons() & Qt::LeftButton)
        {
            IRIVIATool().applyOnScreen("BlurOrSharpen", (int)cursorpos.x(), (int)cursorpos.y());
        }
        break;
    default:
        break;
    }

    updateImageViewArea();

    if (event->button() == m_translateButton)
    {
        m_bMouseTranslate  = true;
        m_lastMousePos  = event->pos();
    }

}

void ImageViewArea::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == m_translateButton)
        m_bMouseTranslate  = false;
}

//void ImageViewArea::mouseDoubleClickEvent(QMouseEvent *event)
//{

//}

void ImageViewArea::wheelEvent(QWheelEvent *event)
{
    QPoint scrollAmount = event->angleDelta();
    scrollAmount.y() > 0 ? zoomIn() : zoomOut();
}

void ImageViewArea::mouseMoveEvent(QMouseEvent *event)
{
    QPointF cursorpos = mapToScene(event->pos());
    QPointF lastcursorpos = mapToScene(m_lastMousePos);
    QVector<QPointF> allpoints;
    genAllPointsWhileMoving(lastcursorpos, cursorpos, allpoints);
    int numPoints = allpoints.size();

    switch(m_enCurToolState) {
    case PencilTool:
        if(event->buttons() & Qt::LeftButton)
        {
            for(int i = 0; i < numPoints; i++)
                IRIVIATool().applyOnScreen("Pencil", (int)allpoints[i].x(), (int)allpoints[i].y());
        }
        break;
    case EraserTool:
        if(event->buttons() & Qt::LeftButton)
        {
            for(int i = 0; i < numPoints; i++)
                IRIVIATool().applyOnScreen("Eraser", (int)allpoints[i].x(), (int)allpoints[i].y());
        }
        break;
    case BlurOrSharpenTool:
        if(event->buttons() & Qt::LeftButton)
        {
            for(int i = 0; i < numPoints; i++)
                IRIVIATool().applyOnScreen("BlurOrSharpen", (int)allpoints[i].x(), (int)allpoints[i].y());
        }
        break;
    default:
        break;
    }

    updateImageViewArea();

    if (m_bMouseTranslate)
    {
        QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos);
        translate(mouseDelta);
    }
    m_lastMousePos = event->pos();

    QPoint cursorp = cursorpos.toPoint();
    emit cursorPosChanged(cursorp);
}

void ImageViewArea::updateImageViewArea()
{
    m_pGraphicsScene->clear();
    m_pGraphicsScene->addPixmap(QPixmap::fromImage(IRIVIAProject::getInstance()->getDisplayQImage()));
}

void ImageViewArea::setEnCurToolState(const ToolState &enCurToolState)
{
    m_enCurToolState = enCurToolState;
    switch (enCurToolState) {
    case PencilTool:
        setCursor(QCursor(Qt::CrossCursor));
        break;
    case EraserTool:
        setCursor(QCursor(Qt::OpenHandCursor));
        break;
    case BlurOrSharpenTool:
        setCursor(QCursor(Qt::PointingHandCursor));
        break;
    default:
        setCursor(QCursor(Qt::ArrowCursor));
        break;
    }
}

void ImageViewArea::genAllPointsWhileMoving(const QPointF &start, const QPointF &end, QVector<QPointF> &allpoints)
{
    double l = 1.0;
    double y = end.y() - start.y();
    double x = end.x() - start.x();

    double angle = std::atan2(y, x);

    int num = std::sqrt(x * x + y * y) / l;
    for(int i = 1; i < num; i++)
    {
        double y = start.y() + (double)i * l * (std::sin(angle));
        double x = start.x() + (double)i * l * (std::cos(angle));
        QPointF p(x, y);
        allpoints.push_back(p);
    }
    allpoints.push_back(end);
}
